
/* 实现用户态接入ENC28J60 SPI网卡
 *
 */
 
#include <lwip/init.h>
#include <lwip/netif.h>
#include <lwip/etharp.h>
#include <lwip/udp.h>
#include <netif/ethernet.h>
struct netif enc28j60_if;
 
#include <linux/spi/spidev.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <poll.h>

#include <stdio.h>
#include <inttypes.h>
#include <errno.h>
#include <string.h>
#include <time.h>

#if 1

u32_t sys_now (void)
{
    struct timespec tspec;
    clock_gettime(CLOCK_MONOTONIC, &tspec);

    return tspec.tv_sec * 1000 + tspec.tv_nsec / 1000000;
}

#endif

int rst_fd = -1;
int cs_fd = -1;
int int_fd = -1;

int spi_fd = -1;

int spi_init(const char *dev)
{
    int ret;
    uint8_t v8;
    uint32_t v32;

    do
    {
        spi_fd = open(dev, O_RDWR | O_NONBLOCK);
        if (spi_fd < 0)
        {
            printf("open(%s) failed, errno: %d\n", dev, errno);
            ret = -1;
            break;
        }

        v8 = SPI_MODE_0;
        ret = ioctl(spi_fd, SPI_IOC_RD_MODE, &v8);
        if (ret < 0)
        {
            printf("ioctl(SPI_IOC_RD_MODE) failed, ret: %d, errno: %d\n", ret, errno);
            break;
        }

        v8 = SPI_MODE_0;
        ret = ioctl(spi_fd, SPI_IOC_WR_MODE, &v8);
        if (ret < 0)
        {
            printf("ioctl(SPI_IOC_WR_MODE) failed, ret: %d, errno: %d\n", ret, errno);
            break;
        }
        
        v8 = 0;
        ret = ioctl(spi_fd, SPI_IOC_RD_LSB_FIRST, &v8);
        if (ret < 0)
        {
            printf("ioctl(SPI_IOC_RD_LSB_FIRST) failed, ret: %d, errno: %d\n", ret, errno);
            break;
        }
        
        v8 = 0;
        ret = ioctl(spi_fd, SPI_IOC_WR_LSB_FIRST, &v8);
        if (ret < 0)
        {
            printf("ioctl(SPI_IOC_WR_LSB_FIRST) failed, ret: %d, errno: %d\n", ret, errno);
            break;
        }
        
        v8 = 8;
        ret = ioctl(spi_fd, SPI_IOC_RD_BITS_PER_WORD, &v8);
        if (ret < 0)
        {
            printf("ioctl(SPI_IOC_RD_BITS_PER_WORD) failed, ret: %d, errno: %d\n", ret, errno);
            break;
        }
        
        v8 = 8;
        ret = ioctl(spi_fd, SPI_IOC_WR_BITS_PER_WORD, &v8);
        if (ret < 0)
        {
            printf("ioctl(SPI_IOC_WR_BITS_PER_WORD) failed, ret: %d, errno: %d\n", ret, errno);
            break;
        }
        
        v32 = 18000000;
        ret = ioctl(spi_fd, SPI_IOC_RD_MAX_SPEED_HZ, &v32);
        if (ret < 0)
        {
            printf("ioctl(SPI_IOC_RD_MAX_SPEED_HZ) failed, ret: %d, errno: %d\n", ret, errno);
            break;
        }
        
        v32 = 18000000;
        ret = ioctl(spi_fd, SPI_IOC_WR_MAX_SPEED_HZ, &v32);
        if (ret < 0)
        {
            printf("ioctl(SPI_IOC_WR_MAX_SPEED_HZ) failed, ret: %d, errno: %d\n", ret, errno);
            break;
        }

        return 0;
    } while(0);

    close(spi_fd);
    spi_fd = -1;

    return ret;
}

void spi_uninit(void)
{
    close(spi_fd);

    return;
}

uint8_t spi_sendbyte(uint8_t w_byte)
{
    int ret;
    uint8_t r_byte = 0xFF;
    struct spi_ioc_transfer xfer;

    memset(&xfer, 0, sizeof(xfer));
    xfer.tx_buf = (__u64)(intptr_t)&w_byte;
    xfer.rx_buf = (__u64)(intptr_t)&r_byte;
    xfer.len = 1;
    xfer.delay_usecs = 2;
    xfer.cs_change = 1;

    ret = ioctl(spi_fd, SPI_IOC_MESSAGE(1), &xfer);
    if (ret < 0)
    {
        printf("ioctl(SPI_IOC_MESSAGE) failed, ret: %d\n", ret);
    }

    return r_byte;
}

int gpio_init(void)
{
    int_fd = open("/sys/class/gpio/gpio23/value", O_RDONLY | O_NONBLOCK);
    rst_fd = open("/sys/class/gpio/gpio24/value", O_WRONLY | O_NONBLOCK);
    cs_fd = open("/sys/class/gpio/gpio25/value", O_WRONLY | O_NONBLOCK);

    write(rst_fd, "1", 1);
}

#define ENC28J60_CSL()   write(cs_fd, "0", 1)
#define ENC28J60_CSH()   write(cs_fd, "1", 1)

/****************************************************************************************************/

/* SPI 操作命令字 { */

/* 读控制寄存器 */
#define ENC28J60_READ_CTRL_REG          0x00
/* 写控制寄存器 */
#define ENC28J60_WRITE_CTRL_REG         0x40

/* 读缓冲区 */
#define ENC28J60_READ_BUF_MEM           0x3A
/* 写缓冲区 */
#define ENC28J60_WRITE_BUF_MEM          0x7A

/* 位域置位 */
#define ENC28J60_BIT_FIELD_SET          0x80
/* 位域清零 */
#define ENC28J60_BIT_FIELD_CLR          0xA0

/* 系统复位 */
#define ENC28J60_SOFT_RESET             0xFF

/* } */


/* 寄存器地址掩码 */
#define ADDR_MASK        0x1F
/* 存储区域掩码 */
#define BANK_MASK        0x60
/* MAC和MII寄存器掩码*/
#define SPRD_MASK        0x80


/* 公共寄存器 { */

/* EIE(ETHERNET INTERRUPT ENABLE REGISTER) 定义 { */
#define EIE                    0x1B
/* Global INT Interrupt Enable bit */
#define EIE_INTIE              0x80
/* Receive Packet Pending Interrupt Enable bit */
#define EIE_PKTIE              0x40
/* DMA Interrupt Enable bit */
#define EIE_DMAIE              0x20
/* Link Status Change Interrupt Enable bit */
#define EIE_LINKIE             0x10
/* Transmit Enable bit */
#define EIE_TXIE               0x08
/* Transmit Error Interrupt Enable bit */
#define EIE_TXERIE             0x02
/* Receive Error Interrupt Enable bit */
#define EIE_RXERIE             0x01
/* } */

/* EIR(ETHERNET INTERRUPT REQUEST (FLAG) REGISTER) 定义 { */
#define EIR                    0x1C
/* Receive Packet Pending Interrupt Flag bit */
#define EIR_PKTIF                       0x40
/* DMA Interrupt Flag bit */
#define EIR_DMAIF                       0x20
/* Link Change Interrupt Flag bit */
#define EIR_LINKIF                      0x10
/* Transmit Interrupt Flag bit */
#define EIR_TXIF                        0x08
/* Transmit Error Interrupt Flag bit */
#define EIR_TXERIF                      0x20
/* Receive Error Interrupt Flag bit */
#define EIR_RXERIF                      0x10
/* } */

/* ESTAT 寄存器bit定义 { */
#define ESTAT                  0x1D
/* INT Interrupt Flag bit */
#define ESTAT_INT                       0x80
/* Ethernet Buffer Error Status bit */
#define ESTAT_BUFER                     0x40
/* Late Collision Error bit */
#define ESTAT_LATECOL                   0x10
/* Receive Busy bit */
#define ESTAT_RXBUSY                    0x04
/* Transmit Abort Error bit */
#define ESTAT_TXABRT                    0x02
/* Clock Ready bit */
#define ESTAT_CLKRDY                    0x01
/* } */

/* ECON2 bit定义 { */
#define ECON2                           0x1E
/* Automatic Buffer Pointer Increment Enable bit */
#define ECON2_AUTOINC                   0x80
/* Packet Decrement bit */
#define ECON2_PKTDEC                    0x40
/* Power Save Enable bit */
#define ECON2_PWRSV                     0x20
/* Voltage Regulator Power Save Enable bit */
#define ECON2_VRPS                      0x08
/* } */

/* ECON1 寄存器bit定义 { */
#define ECON1                  0x1F
/* 发送逻辑reset */
#define ECON1_TXRST                     0x80
/* 接收逻辑reset */
#define ECON1_RXRST                     0x40
/* DMA状态 */
#define ECON1_DMAST                     0x20
/* DMA Checksum Enable bit */
#define ECON1_CSUMEN                    0x10
/* Transmit Request to Send bit */
#define ECON1_TXRTS                     0x08
/* Receive Enable bit */
#define ECON1_RXEN                      0x04
/* 两个 bank 选择位 */
#define ECON1_BSEL1                     0x02
#define ECON1_BSEL0                     0x01
/* } */

/* } */


/* bank0 寄存器  { */
#define ERDPTL            (0x00|0x00)
#define ERDPTH            (0x01|0x00)

#define EWRPTL            (0x02|0x00)
#define EWRPTH            (0x03|0x00)

#define ERXSTL            (0x08|0x00)
#define ERXSTH            (0x09|0x00)

#define ERXRDPTL          (0x0C|0x00)
#define ERXRDPTH          (0x0D|0x00)

#define ERXNDL            (0x0A|0x00)
#define ERXNDH            (0x0B|0x00)

#define ETXSTL            (0x04|0x00)
#define ETXSTH            (0x05|0x00)

#define ETXNDL            (0x06|0x00)
#define ETXNDH            (0x07|0x00)
/* } */


/* bank1 寄存器 { */
#define EHT0              (0x00|0x20)
#define EHT1              (0x01|0x20)
#define EHT2              (0x02|0x20)

/* pattern match mask byte 0 ~ 7*/
#define EPMM0             (0x08|0x20)
#define EPMM1             (0x09|0x20)
#define EPMM2             (0x0A|0x20)
#define EPMM3             (0x0B|0x20)
#define EPMM4             (0x0C|0x20)
#define EPMM5             (0x0D|0x20)
#define EPMM6             (0x0E|0x20)
#define EPMM7             (0x0F|0x20)

/* Pattern Match Checksum  */
#define EPMCSL            (0x09|0x20)
#define EPMCSH            (0x10|0x20)

/* ERXFCON(ETHERNET RECEIVE FILTER CONTROL REGISTER) { */
#define ERXFCON           (0x11|0x20)
/* Unicast Filter Enable bit */
#define ERXFCON_UCEN                    0x80
/* AND/OR Filter Select bit */
#define ERXFCON_ANDOR                   0x40
/* Post-Filter CRC Check Enable bit */
#define ERXFCON_CRCEN                   0x20
/* Pattern Match Filter Enable bit */
#define ERXFCON_PMEN                    0x10
/* Magic Packet™ Filter Enable bit */
#define ERXFCON_MPEN                    0x08
/* Hash Table Filter Enable bit */
#define ERXFCON_HTEN                    0x04
/* Multicast Filter Enable bit */
#define ERXFCON_MCEN                    0x02
/* Broadcast Filter Enable bit */
#define ERXFCON_BCEN                    0x01
/* } */

#define EPKTCNT                            (0x19|0x20)

/* } */


/* bank2 寄存器 { */

/* MACON1(MAC CONTROL REGISTER 1) bit定义 { */
#define MACON1           (0x00|0x40|0x80)
/* Pause Control Frame Transmission Enable bit */
#define MACON1_TXPAUS                   0x08
/* Pause Control Frame Reception Enable bit */
#define MACON1_RXPAUS                   0x04
/* Pass All Received Frames Enable bit */
#define MACON1_PASSALL                  0x02
/* MAC Receive Enable bit */
#define MACON1_MARXEN                   0x01
/* } */

//#define MACON2           (0x01|0x40|0x80)

/* MACON3: MAC CONTROL REGISTER 3 { */
#define MACON3           (0x02|0x40|0x80)
/*  Automatic Pad and CRC Configuration bits */
#define MACON3_PADCFG2      0x80
#define MACON3_PADCFG1      0x40
#define MACON3_PADCFG0      0x20
/* Transmit CRC Enable bit */
#define MACON3_TXCRCEN     0x10
/* Proprietary Header Enable bit */
#define MACON3_PHDREN      0x08
/* Huge Frame Enable bit */
#define MACON3_HFRMEN      0x04
/* Frame Length Checking Enable bit */
#define MACON3_FRMLNEN     0x02
/* MAC Full-Duplex Enable bit */
#define MACON3_FULDPX      0x01
/* } */

/* MACON4: MAC CONTROL REGISTER 4 { */
#define MACON4          (0x03|0x40|0x80)
/* Defer Transmission Enable bit (applies to half duplex only) */
#define MACON4_DEFER        0x40
/* No Backoff During Backpressure Enable bit (applies to half duplex only) */
#define MACON4_BPEN         0x20
/* No Backoff Enable bit (applies to half duplex only) */
#define MACON4_NOBKOFF      0x10
/* } */

/* MABBIPG: MAC BACK-TO-BACK INTER-PACKET GAP REGISTER */
#define MABBIPG          (0x04|0x40|0x80)

/* Non-Back-to-Back Inter-Packet Gap */
#define MAIPGL           (0x06|0x40|0x80)
#define MAIPGH           (0x07|0x40|0x80)

/* Maximum Frame Length */
#define MAMXFLL          (0x0A|0x40|0x80)
#define MAMXFLH          (0x0B|0x40|0x80)

#define MIREGADR         (0x14|0x40|0x80)

#define MIWRL             (0x16|0x40|0x80)
#define MIWRH             (0x17|0x40|0x80)

/* } */


/* bank3 寄存器 { */

#define MAADR5           (0x00|0x60|0x80)
#define MAADR6           (0x01|0x60|0x80)
#define MAADR3           (0x02|0x60|0x80)
#define MAADR4           (0x03|0x60|0x80)
#define MAADR1           (0x04|0x60|0x80)
#define MAADR2           (0x05|0x60|0x80)

/* MISTAT: MII STATUS REGISTER { */
#define MISTAT            (0x0A|0x60|0x80)
#define MISTAT_NVALID     0x04
#define MISTAT_SCAN       0x02
#define MISTAT_BUSY       0x01
/* } */

/* PHY CONTROL REGISTER 1 { */
#define PHCON1              0x00
/* PHY Software Reset bit */
#define PHCON1_PRST         0x8000
/* PHY Loopback bit */
#define PHCON1_PLOOPBK      0x4000
/* PHY Power-Down bit */
#define PHCON1_PPWRSV       0x0800
/* PHY Duplex Mode bit */
#define PHCON1_PDPXMD       0x0100
/* } */

/* PHCON2: PHY CONTROL REGISTER 2 { */
#define PHCON2              0x10
/* PHY Force Linkup bit */
#define PHCON2_FRCLNK       0x4000
/* Twisted-Pair Transmitter Disable bit */
#define PHCON2_TXDIS        0x2000
/* Jabber Correction Disable bit */
#define PHCON2_JABBER       0x0400
/* PHY Half-Duplex Loopback Disable bit */
#define PHCON2_HDLDIS       0x0100
/* } */

/* PHLCON(PHY MODULE LED CONTROL REGISTER) */
/* Bit定义见 DS Page 9 */
#define PHLCON              0x14

/* } */


/* 接收缓冲区起始地址 */
#define RXSTART_INIT                0x00

/* 接收缓冲区停止地址 */
#define RXSTOP_INIT                 (0x1FFF - 0x0600 - 1)

/* 发送缓冲区起始地址 发送缓冲区大小约1500字节*/
#define TXSTART_INIT                (0x1FFF - 0x0600)

/* 发送缓冲区停止地址 */
#define TXSTOP_INIT                 0x1FFF

static uint16_t NextPacketPtr;

static
uint8_t enc28j60ReadOp(uint8_t op, uint8_t address)
{
    uint8_t dat = 0;

    /* CS拉低 使能ENC28J60 */
    ENC28J60_CSL();

    /* 操作码和地址 */
    dat = op | (address & ADDR_MASK);
    /* 通过SPI写数据*/
    spi_sendbyte(dat);

    /* 通过SPI读出数据 */
    dat = spi_sendbyte(0xFF);

    /* 如果是MAC和MII寄存器，第一个读取的字节无效，该信息包含在地址的最高位 */
    if (address & 0x80)
    {
        /* 再次通过SPI读取数据 */
        dat = spi_sendbyte(0xFF);
    }

    /* CS拉高 禁止ENC28J60 */
    ENC28J60_CSH();

    /* 返回数据 */
    return dat;
}

static
void enc28j60WriteOp(uint8_t op, uint8_t address, uint8_t data)
{
    uint8_t dat = 0;
    
    /* 使能ENC28J60 */                                                   
    ENC28J60_CSL();    
    
    /* 通过SPI发送 操作码和寄存器地址 */                         
    dat = op | (address & ADDR_MASK);
    /* 通过SPI1发送数据 */
    spi_sendbyte(dat);
    
    /* 准备寄存器数值 */                             
    dat = data;
    /* 通过SPI发送数据 */
    spi_sendbyte(dat);
    
    /* 禁止ENC28J60 */                      
    ENC28J60_CSH();   
}

static
void enc28j60SetBank(uint8_t address)
{
    static uint8_t  Enc28j60Bank;
    /* 计算本次寄存器地址在存取区域的位置 */
    if ((address & BANK_MASK) != Enc28j60Bank)
    {
        /* 清除ECON1的BSEL1 BSEL0 详见数据手册15页 */
        enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, ECON1, (ECON1_BSEL1|ECON1_BSEL0));
        /* 请注意寄存器地址的宏定义，bit6 bit5代码寄存器存储区域位置 */
        enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, (address & BANK_MASK)>>5);
        /* 重新确定当前寄存器存储区域 */
        Enc28j60Bank = (address & BANK_MASK);
    }
}

static
uint8_t enc28j60Read(uint8_t address)
{
    /* 设定寄存器地址区域 */
    enc28j60SetBank(address);
    /* 读取寄存器值 发送读寄存器命令和地址 */
    return enc28j60ReadOp(ENC28J60_READ_CTRL_REG, address);
}

static
void enc28j60Write(uint8_t address, uint8_t data)
{
    /* 设定寄存器地址区域 */
    enc28j60SetBank(address);
    /* 写寄存器值 发送写寄存器命令和地址 */
    enc28j60WriteOp(ENC28J60_WRITE_CTRL_REG, address, data);
}

static
void enc28j60PhyWrite(uint8_t address, unsigned int data)
{
    /* 向MIREGADR写入地址 详见数据手册19页*/
    enc28j60Write(MIREGADR, address);

    /* 写入低8位数据 */
    enc28j60Write(MIWRL, data);
    /* 写入高8位数据 */
    enc28j60Write(MIWRH, data>>8);

    /* 等待PHY寄存器写入完成 */
    while(enc28j60Read(MISTAT) & MISTAT_BUSY);
}

static
void enc28j60ReadBuffer(unsigned int len, uint8_t* pdata)
{
    /* 使能ENC28J60 */
    ENC28J60_CSL();

    /* 通过SPI发送读取缓冲区命令*/
    spi_sendbyte(ENC28J60_READ_BUF_MEM);

    /* 循环读取 */
    while (len)
    {
        len--;
        /* 读取数据 */
        *pdata = spi_sendbyte(0);
        /* 地址指针累加 */
        pdata++;
    }

    /* 增加字符串结尾 便于操作 */
    *pdata='\0';

    /* 禁止ENC28J60 */
    ENC28J60_CSH();
}

static
void enc28j60WriteBuffer(uint16_t len, uint8_t* pdata)
{
    /* 使能ENC28J60 */
    ENC28J60_CSL();

    /* 通过SPI发送写取缓冲区命令*/
    spi_sendbyte(ENC28J60_WRITE_BUF_MEM);

    /* 循环发送 */
    while (len)
    {
        len--;
        /* 发送数据 */
        spi_sendbyte(*pdata);
        /* 地址指针累加 */
        pdata++;
    }

    /* 禁止ENC28J60 */
    ENC28J60_CSH();
}

void enc28j60PacketSend(uint16_t len, uint8_t* packet)
{
    /* 查询发送逻辑复位位 */
    while((enc28j60Read(ECON1) & ECON1_TXRTS)!= 0);
    
    /* 设置发送缓冲区起始地址 */   
    enc28j60Write(EWRPTL, TXSTART_INIT & 0xFF);
    enc28j60Write(EWRPTH, TXSTART_INIT >> 8);
    
    /* 设置发送缓冲区结束地址 该值对应发送数据包长度 */  
    enc28j60Write(ETXNDL, (TXSTART_INIT + len) & 0xFF);
    enc28j60Write(ETXNDH, (TXSTART_INIT + len) >>8);
    
    /* 发送之前发送控制包格式字 */
    enc28j60WriteOp(ENC28J60_WRITE_BUF_MEM, 0, 0x00);

    /* 通过ENC28J60发送数据包 */
    enc28j60WriteBuffer(len, packet);
    
    /* Clear EIR.TXIF, set EIE.TXIE and set EIE.INTIE
     * to enable an interrupt when done (if desired).
     */

    /* 开始发送 */
    enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRTS);

    /* 复位发送逻辑的问题 */
    if ((enc28j60Read(EIR) & EIR_TXERIF))
    {
        enc28j60SetBank(ECON1);
        enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRTS);
    }
}

/* DS,P34 Normal network nodes are designed to handle packets that are 1518 bytes or less. */
#define MAX_FRAMELEN  1518
uint8_t eth_frame[MAX_FRAMELEN];

void enc28j60PacketReceive(void)
{
    uint16_t rxstat;
    uint16_t len;

    /* 是否收到以太网数据包 */
    while (enc28j60Read(EPKTCNT) > 0)
    {
        /* 设置接收缓冲器读指针 */
        enc28j60Write(ERDPTL, (NextPacketPtr));
        enc28j60Write(ERDPTH, (NextPacketPtr)>>8);

        /* 接收数据包结构示例 数据手册43页 */
        /* 读下一个包的指针 */
        NextPacketPtr  = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0);
        NextPacketPtr |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0) << 8;

        /* DS P44 TABLE 7-3: RECEIVE STATUS VECTORS */

        /* 读包的长度 */
        len  = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0);
        len |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0) << 8;
        /* 去除CRC校验部分 */
        len -= 4;

        /* 读取接收状态 */
        rxstat  = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0);
        rxstat |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0) << 8;

#if 0
        /* 限制检索的长度  */
        if (len > maxlen-1)
        {
            len = maxlen-1;
        }
#endif
        //printf("len: %" PRIu16 ", rxstat: %04X\n", len, rxstat);

        /* 检查CRC和符号错误 */
        /* ERXFCON_CRCEN 是默认设置。通常我们不需要检查 */

        /* Received Ok */
        if ((rxstat & 0x80) == 0)
        {
            //无效的
            len = 0;
        }
        else
        {
            enc28j60ReadBuffer(len, eth_frame);
            
          #if 0
            uint16_t type = *(uint16_t*)&eth_frame[12];
            if (type == 0x0008)
            {
                printf("IP, dst: %02X-%02X-%02X-%02X-%02X-%02X, src: %02X-%02X-%02X-%02X-%02X-%02X, type: %02X%02X\n", 
                    eth_frame[0], eth_frame[1], eth_frame[2],
                    eth_frame[3], eth_frame[4], eth_frame[5],
                    eth_frame[6], eth_frame[7], eth_frame[8],
                    eth_frame[9], eth_frame[10], eth_frame[11],
                    eth_frame[12], eth_frame[13]);
            }
          #endif
            
          #if 0
            uint16_t type = *(uint16_t*)&eth_frame[12];
            if (type == 0x0608)
            {
                printf("ARP, dst: %02X-%02X-%02X-%02X-%02X-%02X, src: %02X-%02X-%02X-%02X-%02X-%02X, type: %02X%02X\n", 
                    eth_frame[0], eth_frame[1], eth_frame[2],
                    eth_frame[3], eth_frame[4], eth_frame[5],
                    eth_frame[6], eth_frame[7], eth_frame[8],
                    eth_frame[9], eth_frame[10], eth_frame[11],
                    eth_frame[12], eth_frame[13]);
            }
          #endif

          #if 1
            printf("dst: %02X-%02X-%02X-%02X-%02X-%02X, src: %02X-%02X-%02X-%02X-%02X-%02X, type: %02X%02X\n", 
                eth_frame[0], eth_frame[1], eth_frame[2],
                eth_frame[3], eth_frame[4], eth_frame[5],
                eth_frame[6], eth_frame[7], eth_frame[8],
                eth_frame[9], eth_frame[10], eth_frame[11],
                eth_frame[12], eth_frame[13]);
          #endif
            struct pbuf *pb = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
            pbuf_take(pb, eth_frame, len);
            enc28j60_if.input(pb, &enc28j60_if);
        }

        /* 移动接收缓冲区 读指针*/
        enc28j60Write(ERXRDPTL, (NextPacketPtr));
        enc28j60Write(ERXRDPTH, (NextPacketPtr)>>8);

        /* In addition to advancing the Receive Buffer Read Pointer, 
         * after each packet is fully processed, the host
         * controller must write a ‘1’ to the ECON2.PKTDEC bit.
         *
         * Doing so will cause the EPKTCNT register to decrement by 1
         */
        /* 数据包递减 */
        enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PKTDEC);
    }
}


void enc28j60Init(uint8_t* macaddr)
{
    /* 禁止ENC28J60 */
    ENC28J60_CSH();

    /* ENC28J60软件复位 该函数可以改进*/
    enc28j60WriteOp(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET);
    /*查询ESTAT.CLKRDY位*/
    while (!(enc28j60Read(ESTAT) & ESTAT_CLKRDY));

    /* 设置接收缓冲区起始地址 该变量用于每次读取缓冲区时保留下一个包的首地址 */
    NextPacketPtr = RXSTART_INIT;
    
    /* 设置接收缓冲区 起始指针*/
    enc28j60Write(ERXSTL, RXSTART_INIT & 0xFF);
    enc28j60Write(ERXSTH, RXSTART_INIT >> 8);
    
    /* 设置接收缓冲区 读指针*/
    enc28j60Write(ERXRDPTL, RXSTART_INIT&0xFF);
    enc28j60Write(ERXRDPTH, RXSTART_INIT>>8);
    
    /* 设置接收缓冲区 结束指针 */
    enc28j60Write(ERXNDL, RXSTOP_INIT&0xFF);
    enc28j60Write(ERXNDH, RXSTOP_INIT>>8);
    
    /* 设置发送缓冲区 起始指针 */
    enc28j60Write(ETXSTL, TXSTART_INIT&0xFF);
    enc28j60Write(ETXSTH, TXSTART_INIT>>8);
    
    /* 设置发送缓冲区 结束指针 */
    enc28j60Write(ETXNDL, TXSTOP_INIT&0xFF);
    enc28j60Write(ETXNDH, TXSTOP_INIT>>8);

  #if 1
    /* 使能单播过滤 / 多播 / 广播, 并启用CRC校验
     */
    enc28j60Write(ERXFCON, ERXFCON_UCEN | ERXFCON_CRCEN | ERXFCON_MCEN | ERXFCON_BCEN);
  #else
    /* 使能单播过滤 使能CRC校验 使能 格式匹配自动过滤 
     */
    enc28j60Write(ERXFCON, ERXFCON_UCEN | ERXFCON_CRCEN | ERXFCON_PMEN);

    enc28j60Write(EPMM0, 0x3f);
    enc28j60Write(EPMM1, 0x30);
    
    enc28j60Write(EPMCSL, 0xf9);
    enc28j60Write(EPMCSH, 0xf7);

    enc28j60Write(EPMOH, 0);
    enc28j60Write(EPMOL, 0);
  #endif

    /* 使能MAC接收 允许MAC发送暂停控制帧 当接收到暂停控制帧时停止发送*/
    /* 数据手册34页 */
    enc28j60Write(MACON1, MACON1_MARXEN | MACON1_TXPAUS | MACON1_RXPAUS);

    /* 退出复位状态 */
    //enc28j60Write(MACON2, 0x00);

    /* 用0填充所有短帧至60字节长 并追加一个CRC 发送CRC使能 帧长度校验使能 MAC全双工使能*/
    /* 提示 由于ENC28J60不支持802.3的自动协商机制， 所以对端的网络卡需要强制设置为全双工 */
    enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, MACON3, MACON3_PADCFG0|MACON3_TXCRCEN|MACON3_FRMLNEN|MACON3_FULDPX);

    /* 全双工，不需配置 MACON4 */

    /* 最大帧长度 */
    enc28j60Write(MAMXFLL, MAX_FRAMELEN & 0xFF);
    enc28j60Write(MAMXFLH, MAX_FRAMELEN >> 8);

    /* Configure the Back-to-Back Inter-Packet Gap register */
    /* 填入全双工模式的默认值 */
    enc28j60Write(MABBIPG, 0x15);
    
    /* Configure the Non-Back-to-Back Inter-Packet Gap register */
    /* 填入默认值 */
    enc28j60Write(MAIPGL, 0x12);
    enc28j60Write(MAIPGH, 0x0C);

    /* 大部分情况，不需配置 MACLCON1 / MACLCON2 */

    /* 写入MAC地址 */
    enc28j60Write(MAADR1, macaddr[0]);     
    enc28j60Write(MAADR2, macaddr[1]);
    enc28j60Write(MAADR3, macaddr[2]);
    enc28j60Write(MAADR4, macaddr[3]);
    enc28j60Write(MAADR5, macaddr[4]);
    enc28j60Write(MAADR6, macaddr[5]);

    /********** 开始配置PHY **********/

    /* 配置PHY为全双工，必须和 MACON3_FULDPX 相对应 */
    enc28j60PhyWrite(PHCON1, PHCON1_PDPXMD);

    /* LED状态 */
    /*
     * 00,11,0100,0111,01,1,0
     * 0100 LEDA, Display link status
     * 0111 LEDB, Display transmit and receive activity (stretchable)
     * 01 LFRQ<1:0>, Stretch LED events by TMSTRCH
     * 1 STRCH, Stretchable LED events will cause lengthened LED pulses based on LFRQ<1:0> configuration
     */
    enc28j60PhyWrite(PHLCON, 0x0476);

    /* 半双工回环禁止 */
    enc28j60PhyWrite(PHCON2, PHCON2_HDLDIS);

    /* 返回BANK0 */     
    enc28j60SetBank(ECON1);

    /* 使能中断 全局中断 / 接收中断 / 接收错误中断 */
    enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, EIE, EIE_INTIE | EIE_PKTIE | EIE_RXERIE);

    /* 接收使能位 */
    enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN);
}

/***************************************************************/

void enc28j60_isr(void)
{
    uint8_t eir;

    //printf("\nenc28j60_isr\n");

    enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, EIE, EIE_INTIE);

    eir = enc28j60Read(EIR);
    if (eir & EIR_PKTIF)
    {
        //printf("rcv packet\n");
        enc28j60PacketReceive();
    }
    if (eir & EIR_LINKIF)
    {
        printf("link change\n");
    }
    if (eir & EIR_TXERIF)
    {
        printf("recv error\n");
    }
    if (eir & EIR_RXERIF)
    {
        printf("send error\n");
    }

    enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, EIE, EIE_INTIE);
}

#if 0
static void toggle_led(void)
{
    static int flag = 0;
    if (flag & 0x01)
    {
        /* LEDA On, LEDB Off */
        enc28j60PhyWrite(PHLCON, 0x3896);
    }
    else
    {
        /* LEDA Off, LEDB On */
        enc28j60PhyWrite(PHLCON, 0x3986);
    }
    flag++;

    return;
}
#endif

static
err_t enc28j60_output(struct netif *netif, struct pbuf *p)
{
    struct pbuf *q;
    for (q = p; q != NULL; q = q->next)
    {
        enc28j60PacketSend(q->len, (uint8_t*)q->payload);
    }

    return ERR_OK;
}

static
err_t enc28j60_if_init(struct netif *netif)
{
	/* OUI 00-04-A3 (hex): Microchip Technology, Inc. */
	uint8_t mac[6] = {0x00, 0x04, 0xA3, 0x12, 0x34, 0x56};

    netif->name[0] = 's';
    netif->name[1] = '0';

    netif->output = etharp_output;
    netif->linkoutput = enc28j60_output;

    netif->mtu = 1500;

    netif->flags = NETIF_FLAG_UP | NETIF_FLAG_BROADCAST | NETIF_FLAG_LINK_UP | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET;

    netif->hwaddr_len = 6;
    netif->hwaddr[0] = mac[0];
    netif->hwaddr[1] = mac[1];
    netif->hwaddr[2] = mac[2];
    netif->hwaddr[3] = mac[3];
    netif->hwaddr[4] = mac[4];
    netif->hwaddr[5] = mac[5];

    enc28j60Init(mac);

    return ERR_OK;
}

void udp_data_sink(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
{
    printf("udp: src: %s:%u\n", ip4addr_ntoa(addr), port);
    return;
}

int main(int argc, char *argv[])
{
    int ret;
    struct udp_pcb *udp;

    ret = spi_init("/dev/spidev0.0");
    if (ret < 0)
    {
        printf("spi_init() failed\n");
        return -1;
    }

    gpio_init();

    lwip_init();

    {
        ip4_addr_t addr;
        ip4_addr_t netmask;
        ip4_addr_t gw;
        IP4_ADDR(&addr, 192, 168, 127, 251);
        IP4_ADDR(&netmask, 255, 255, 255, 0);
        IP4_ADDR(&gw, 192, 168, 127, 1);

        netif_add(&enc28j60_if, &addr, &netmask, &gw, NULL, enc28j60_if_init, ethernet_input);

        udp = udp_new();
        udp_bind(udp, &addr, 3398);
        udp_bind_netif(udp, &enc28j60_if);
        udp_recv(udp, udp_data_sink, NULL);
    }

    for(;;)
    {
        struct pollfd pfd = {.fd = int_fd, .events = (POLLPRI | POLLERR), .revents = 0};
        ret = poll(&pfd, 1, 10);
        if (ret > 0)
        {
            char buff[32];
            lseek(int_fd, 0, SEEK_SET);
            while (read(int_fd, buff, sizeof(buff)) > 0);
            
            enc28j60_isr();
        }

        sys_check_timeouts();
    }

    spi_uninit();

    return 0;
}
